package com.me.study.producerAndConsumer;

import com.me.common.util.SleepUtil;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用Lock中Condition的 await/signalAll 实现生产者-消费者<p>
 *
 * @author ME
 * @date   2019/3/6 16:41
 */
public class AwaitSignal {

    private static ReentrantLock lock = new ReentrantLock();
    private static Condition full = lock.newCondition();
    private static Condition empty = lock.newCondition();

    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        CyclicBarrier barrier = new CyclicBarrier(15);
        ExecutorService executor = Executors.newFixedThreadPool(15);

        for (int i = 0; i < 5; i++) {
            executor.execute(new Producer(barrier, linkedList, 20, lock, i));
        }

        System.out.println();
        for (int i = 0; i < 10; i++) {
            executor.execute(new Consumer(barrier, linkedList, lock, i));
        }

    }

    static class Producer implements Runnable {
        private CyclicBarrier barrier;
        private List<Integer> list;
        private int maxLength;
        private Lock lock;
        private int name;

        /**
         *
         * @param list  实际存商品的容器
         * @param maxLength 存放商品的容器的最大容量
         * @param lock  锁
         */
        public Producer(CyclicBarrier barrier, List list, int maxLength, Lock lock, int name) {
            this.barrier = barrier;
            this.list = list;
            this.maxLength = maxLength;
            this.lock = lock;
            this.name = name;
        }

        @Override
        public void run() {
            Thread.currentThread().setName("生产者" + name);

            try {
                barrier.await();
                boolean flag = true;
                while (true) {
                    lock.lock();
                    try {
                        while (list.size() >= maxLength) {
                            System.out.println("生产者" + Thread.currentThread().getName() + "  list以达到最大容量，进行wait");
                            // 把当前线程放入 full 等待队列
                            full.await();
                            System.out.println("生产者" + Thread.currentThread().getName() + "  退出wait");
                        }

                        SleepUtil.seconds(1);
                        Random random = new Random();
                        int i = random.nextInt();
                        list.add(i);
                        System.out.println("生产者" + Thread.currentThread().getName() + " 生产数据" + i);
                        // 唤醒 empty 等待队列的线程
                        empty.signalAll();
                        flag = !flag;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }


    static class Consumer implements Runnable {
        private CyclicBarrier barrier;
        private List<Integer> list;
        private Lock lock;
        private int name;

        /**
         *
         * @param list  实际存商品的容器
         * @param lock  锁
         */
        public Consumer(CyclicBarrier barrier, List list, Lock lock, int name) {
            this.barrier = barrier;
            this.list = list;
            this.lock = lock;
            this.name = name;
        }

        @Override
        public void run() {
            Thread.currentThread().setName("消费者" + name);

            try {
                this.barrier.await();
                while (true) {
                    lock.lock();
                    try {
                        while (list.isEmpty()) {
                            System.out.println("消费者" + Thread.currentThread().getName() + "  list为空，进行wait");
                            // 把当前线程放入 empty 等待队列
                            empty.await();
                            System.out.println("消费者" + Thread.currentThread().getName() + "  退出wait");
                        }

                        SleepUtil.seconds(1);
                        Integer element = list.remove(0);
                        System.out.println("消费者" + Thread.currentThread().getName() + "  消费数据：" + element);
                        // 唤醒 full 等待队列的线程
                        full.signalAll();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

}
